#include <mystdio.h>
#include <fonts.h>
#include <asm/system.h>

#include <asm/io.h>
//static unsigned char vga_font[CMAPSIZE];

/**********************************************************
 * Private kernel variables                               *
 **********************************************************/
//extern static const unsigned char* vga_font;
//extern unsigned char* vga_font;
//extern const unsigned char* get_vga_font();
//unsigned char* vga_font;
/* Declaration of private functions */
void set_palette(int start, int end, unsigned char *rgb);
void putfont8(unsigned char* vram, int xsize, int x, int y, char color, unsigned char c);

//void init_mouse_cursor(int xsize, int x,int y);
void putblock8x8(unsigned char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char *buf, int bxsize);
void getblock8x8(unsigned char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char *buf, int bxsize);
void init_fstdio(int xsize, int ysize);

/**********************************************************
 * Public Kernel API functions                            *
 **********************************************************/

/* void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
        int x, y;
        for (y = y0; y <= y1; y++) {
                for (x = x0; x <= x1; x++)
                        vram[y * xsize + x] = c;
                        //vram[2*(y * xsize + x)+1] = c;
        }
        return;
} */

void init_fstdio(int xsize, int ysize){
       //load_vga_font(vga_font);
       //vga_font=get_vga_font();
       init_palette();
       init_screen(xsize, ysize);
}
       
void boxfill8(unsigned char* vram, int xsize, int ysize, unsigned char c, int x0, int y0, int x1, int y1){
    /*
    * This function will draw a box (rectangle) on the screen which has width xsize
    * c is for color
    * (x0, y0) and (x1, y1) are two diagonals of the box. These are absolute coordinates
    */
    int x, y;
    x0 = x0 < 0 ? xsize + x0 : x0;
    y0 = y0 < 0 ? ysize + y0 : y0;
    x1 = x1 < 0 ? xsize + x1 : x1;
    y1 = y1 < 0 ? ysize + y1 : y1;
    if(y0 > y1){
        y = y0; y0 = y1; y1 = y;
    }
    if(x0 > x1){
        x = x0; x0 = x1; x1 = x;
    }

    for (y = y0; y <= y1; y++){
        for(x = x0; x <= x1; x++){
            //vram[y * xsize + x] = c;
            writem8(vram, y * xsize + x, c);
        }
    }
}

void writem8(unsigned char *vram, int pos, unsigned char c){
   if (vram==0){
       write_mem8(pos, c);
   }
   else{
       vram[pos]=c;
   }
}

unsigned char readm8(unsigned char *vram, int pos){
   if (vram==0){
       return read_mem8(pos);
   }
   else{
       return vram[pos];
   }
}

void init_palette()
{
    //static unsigned char table_rgb[16 * 3] = {
    unsigned char table_rgb[16 * 3] = {
        0x00, 0x00, 0x00, // 0: black
        0xff, 0x00, 0x00, // 1: red
        0x00, 0xff, 0x00, // 2. green
        0xff, 0xff, 0x00, // 3. yellow
        0x00, 0x00, 0xff, // 4. blue
        0xff, 0x00, 0xff, // 5. purple
        0x00, 0xff, 0xff, // 6. light blue
        0xff, 0xff, 0xff, // 7, white
        0xc6, 0xc6, 0xc6, // 8. light grey
        0x84, 0x00, 0x00, // 9. dark red
        0x00, 0x84, 0x00, // 10, dark green
        0x84, 0x84, 0x00, // 11. dark yellow
        0x00, 0x00, 0x84, // 12. dark blue
        0x84, 0x00, 0x84, // 13. dark purple
        0x00, 0x84, 0x84, // 14. light dark blue
        0x84, 0x84, 0x84  // 15. dark grey
        };
        set_palette(0, 15, table_rgb);
        return;

        /* static char <96>½<97>ß<82>Í<81>A<83>f<81>[<83>^<82>É<82>µ<82>©<8e>g<82>¦<82>È<82>¢<82>¯<82>ÇDB<96>½<97>ß<91><8a><93><96> */
}

void init_screen(int xsize, int ysize)
{
        unsigned char* vram=0;
        //boxfill8(vram, xsize, ysize, LIGHTDARKBLUE,  0,     0,   -1,  -19);
        boxfill8(vram, xsize, ysize, DARKYELLOW,  0,     0,   -1,  -19);
        boxfill8(vram, xsize, ysize, LIGHTGREY,      0,   -18,   -1,  -18);
        boxfill8(vram, xsize, ysize, WHITE,          0,   -17,   -1,  -17);
        boxfill8(vram, xsize, ysize, LIGHTGREY,      0,   -16,   -1,   -1);

        boxfill8(vram, xsize, ysize, WHITE,          3,   -14,   59,  -14);
        boxfill8(vram, xsize, ysize, WHITE,          2,   -14,    2,   -4);
        boxfill8(vram, xsize, ysize, DARKGREY,       3,    -4,   59,   -4);
        boxfill8(vram, xsize, ysize, DARKGREY,      59,   -13,   59,   -5);
        boxfill8(vram, xsize, ysize, BLACK,          2,    -3,   59,   -3);
        boxfill8(vram, xsize, ysize, BLACK,         60,   -14,   60,   -3);

        boxfill8(vram, xsize, ysize, DARKGREY,     -47,  -14,   -4,   -14);
        boxfill8(vram, xsize, ysize, DARKGREY,     -47,  -13,  -47,    -4);
        boxfill8(vram, xsize, ysize, WHITE,        -47,   -3,   -4,    -3);
        boxfill8(vram, xsize, ysize, WHITE,         -3,  -14,   -3,    -3);
        putfonts8_asc(vram, xsize, xsize/2, ysize-16, LIGHTDARKBLUE, "QOS");
        return;
}

void putfont8(unsigned char* vram, int xsize, int x, int y, char color, unsigned char c){ 
//, unsigned char *font){
	int i,j;
	int p;
        unsigned char d /* data */;
	j=16*c;
	for (i = 0; i < 16; i++) {
		p = (y + i) * xsize + x;
		d = vga_font[i+j];
        // set the color for the corresponding 8 pixels.
		if ((d & 0x80) != 0) { writem8(vram, p+0, color); }
		if ((d & 0x40) != 0) { writem8(vram, p+1, color); }
		if ((d & 0x20) != 0) { writem8(vram, p+2, color); }
		if ((d & 0x10) != 0) { writem8(vram, p+3, color); }
		if ((d & 0x08) != 0) { writem8(vram, p+4, color); }
		if ((d & 0x04) != 0) { writem8(vram, p+5, color); }
		if ((d & 0x02) != 0) { writem8(vram, p+6, color); }
		if ((d & 0x01) != 0) { writem8(vram, p+7, color); }
	}
	return;
}

void putfonts8_asc(unsigned char* vram, int xsize, int x, int y, char c, unsigned char *s)
  //,   unsigned char *font)
{
        //extern char hankaku[4096];
        for (; *s != 0x00; s++) {
                putfont8(vram, xsize, x, y, c, *s);
                x += 8;
        }
        return;
}


// no auto wrap
// x, and y are the index of charactor location on the screen. 
// x = 1 => pixel location x * 8
// y = 2 => pixel location y * 16

/* put buf contents back to vram*/
void putblock8x8(unsigned char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char *buf, int bxsize){
    int x, y;
    for(y = 0; y < pysize; y++){
        for(x = 0; x < pxsize; x++){
            writem8(vram, (py0+y) * vxsize + (px0 + x), buf[y * bxsize + x]);
        }
    }
}

/* get buf contents from vram*/
void getblock8x8(unsigned char* vram, int vxsize, int pxsize, int pysize, int px0, int py0, char *buf, int bxsize){
    int x, y;
    for(y = 0; y < pysize; y++){
        for(x = 0; x < pxsize; x++){
            buf[y * bxsize + x] = readm8(vram, (py0+y) * vxsize + (px0 + x));
        }
    }
}

void putblock8_8(unsigned char* vram, int vxsize, int pxsize,
        int pysize, int px0, int py0, char *buf, int bxsize)
{
        int x, y;
        for (y = 0; y < pysize; y++) {
          for (x = 0; x < pxsize; x++) {
            writem8(vram, (py0 + y) * vxsize + (px0 + x), buf[y * bxsize + x]);
                }
        }
        return;
}

void putfont8bck(unsigned char* vram, int xsize, int ysize, int px0, int py0, 
int px1, int py1, unsigned char color, unsigned char bck, unsigned c){
            boxfill8(vram, xsize, ysize, bck, px0, py0, px1, py1);
            putfont8(vram, xsize, px0, py0, color, c);
}

void set_palette(int start, int end, unsigned char *rgb)
{
        int i, eflags;
        eflags = io_load_eflags();      /* <8a><84><82>è<8d><9e><82>Ý<8b><96><89>Â<83>t<83><89><83>O<82>Ì<92>l<82>ð<8b>L<98>^<82>·<82>é */
        //eflags = load_eflags();
         //io_cli();                                       // <8b><96><89>Â<83>t<83><89><83>O<82>ð0<82>É<82>µ<82>Ä<8a><84><82>è<8d><9e><82>Ý<8b>Ö<8e>~<82>É<82>·<82>é 
         cli();
        //port_byte_out(0x03c8, start);
        //outb_p(0x03c8, start);
        io_out8(0x03c8, start);
         for (i = start; i <= end; i++) {
                //outb_p(0x03c9, (int)rgb[0] / 4);
                //outb_p(0x03c9, (int)rgb[1] / 4);
                //outb_p(0x03c9, (int)rgb[2] / 4);
                io_out8(0x03c9, (int)rgb[0] / 4);
                io_out8(0x03c9, (int)rgb[1] / 4);
                io_out8(0x03c9, (int)rgb[2] / 4);
              //  port_byte_out(0x03c9, rgb[0] / 4);
              //  port_byte_out(0x03c9, rgb[1] / 4);
              //  port_byte_out(0x03c9, rgb[2] / 4); 
                rgb += 3;
        } 
        
        io_store_eflags(eflags);        // <8a><84><82>è<8d><9e><82>Ý<8b><96><89>Â<83>t<83><89><83>O<82>ð<8c>³<82>É<96>ß<82>· 
         //store_eflags(eflags);
        
        //io_sti();
        return;
}

/*void memory_copy(u8 *source, u8 *dest, int nbytes) {
    int i;
    for (i = 0; i < nbytes; i++) {
        *(dest + i) = *(source + i);
    }
}

void memory_set(u8 *dest, u8 val, u32 len) {
    u8 *temp = (u8 *)dest;
    for ( ; len != 0; len--) *temp++ = val;
}*/

void make_window8(unsigned char *buf, int xsize, int ysize, char *title)
{
        //static char closebtn[14][16] = {
        char closebtn[14][16] = {
                "OOOOOOOOOOOOOOO@",
                "OQQQQQQQQQQQQQ$@",
                "OQQQQQQQQQQQQQ$@",
                "OQQQ@@QQQQ@@QQ$@",
                "OQQQQ@@QQ@@QQQ$@",
                "OQQQQQ@@@@QQQQ$@",
                "OQQQQQQ@@QQQQQ$@",
                "OQQQQQ@@@@QQQQ$@",
                "OQQQQ@@QQ@@QQQ$@",
                "OQQQ@@QQQQ@@QQ$@",
                "OQQQQQQQQQQQQQ$@",
                "OQQQQQQQQQQQQQ$@",
                "O$$$$$$$$$$$$$$@",
                "@@@@@@@@@@@@@@@@"
        };
        int x, y;
        char c;
        boxfill8(buf, xsize, ysize, LIGHTGREY, 0,         0,         xsize - 1, 0        );
        boxfill8(buf, xsize, ysize, WHITE, 1,         1,         xsize - 2, 1        );
        boxfill8(buf, xsize, ysize, LIGHTGREY, 0,         0,         0,         ysize - 1);
        boxfill8(buf, xsize, ysize, WHITE, 1,         1,         1,         ysize - 2);
        boxfill8(buf, xsize, ysize, LIGHTGREY, xsize - 2, 1,         xsize - 2, ysize - 2);
        boxfill8(buf, xsize, ysize, BLACK, xsize - 1, 0,         xsize - 1, ysize - 1);
        boxfill8(buf, xsize, ysize, DARKYELLOW, 2,         2,         xsize - 3, ysize - 3);
        boxfill8(buf, xsize, ysize, DARKBLUE, 3,         3,         xsize - 4, 20       );
        boxfill8(buf, xsize, ysize, DARKYELLOW, 1,         ysize - 2, xsize - 2, ysize - 2);
        boxfill8(buf, xsize, ysize, BLACK, 0,         ysize - 1, xsize - 1, ysize - 1);
        putfonts8_asc(buf, xsize, 24, 4, WHITE, title);
        for (y = 0; y < 14; y++) {
                for (x = 0; x < 16; x++) {
                        c = closebtn[y][x];
                        if (c == '@') {
                                c = BLACK;
                        } else if (c == '$') {
                                c = DARKYELLOW;
                        } else if (c == 'Q') {
                                c = LIGHTGREY;
                        } else {
                                c = WHITE;
                        }
                        buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
                }
        }
        return;
}

